//******************************************************************************
//  Lab 9a - Etch-a-Sketch
//
//  Description:
//
//	"Write a C language program that uses the sampled values from two
//	potentiometers to draw (etch) lines on the LCD. Use a low-pass filter
//	to smooth out the sampled values. Program one push button to clear
//	the LCD and another to toggle the size of the drawing pen. Display
//	the pen coordinates in the lower right corner of the display."
//
//   Author:	Brady Eisert, Keith Thompson, Tyler Hale
//				November 2012
//
//  Built with Code Composer Studio Version: 5.2.0.00069
//*******************************************************************************
//
#include "etch-a-sketch.h"
//--SYSTEM CONSTANTS/VARIABLES--------------------------------------------------
//

volatile int counter, b_light, brush_size, debounce_counter, clear_lcd, toggle_point_size;
volatile int WDT_cps_cnt;				// WD counts/second

extern const uint16 byu1_image[];				// BYU logo
extern const uint16 etch_a_sketch_image[];		// etch-a-sketch image
extern const uint16 etch_a_sketch1_image[];		// etch-a-sketch writing

//--main------------------------------------------------------------------------
//
void main(void)
{
	initBoard();

	// update display (interrupts enabled)
	lcd_clear();								// clear LCD
	uint16 x_prev = 1023 - ADC_read(LEFT_POT);		// Initialize the previous points to the current value as not to create awkward lines
	uint16 y_prev = 1023 - ADC_read(RIGHT_POT);

	while (1)									// GAME LOOP
	{
		draw(&x_prev, &y_prev); 				// Handles the acquisition of coordinates and the drawing of them

		if (b_light)
		{
			lcd_backlight(ON);
		}
		else
		{
			lcd_backlight(OFF);
		}
		if(clear_lcd)
		{
			lcd_clear();
			clear_lcd = 0;
		}
		if(toggle_point_size)
		{
			if(brush_size == 1)
			{
				brush_size = 3;
			}
			else
			{
				brush_size = 1;
			}
			toggle_point_size = 0;
		}
	}
} // end main

void initBoard(void)
{
	ERROR2(RBX430_init(_8MHZ));					// init RBX430 board
	ERROR2(lcd_init());							// init lcd
	ERROR2(ADC_init());							// init a/d converter

	// configure Watchdog
	WDT_cps_cnt = WDT_CPS;						// set WD 1 second counter
	WDTCTL = WDT_CTL;							// set WC interval to ~32ms
	IE1 |= WDTIE;								// enable WDT interrupt

	P1SEL = 0x00;	             				// select GPIO
	P1OUT = 0x0f;	            				// turn off all output pins
	P1REN = 0x0f;	             				// pull-up P1.0-3
	P1DIR = 0xc0;	             				// P1.0-5 input, P1.6-7 output
	P1IE |= 0x0f;
	P1IFG &= ~0x0f;

	__bis_SR_register(GIE);						// enable interrupts

	// INITIALIZE ALL GLOBAL VARIABLES
	b_light = 0;
	counter = 0;
	toggle_point_size = 0;
	clear_lcd = 0;
	debounce_counter = 0;
	brush_size = 1;
}

void getCoordinates(uint16 *L_pot, uint16 *R_pot)
{

	// FILTER SAMPLES FROM POTs
	uint16 l_pot_temp = 0;
	uint16 r_pot_temp = 0;
	int i;
	for(i = 0; i < NUM_SAMPLES; i++)
	{
		r_pot_temp += 1023 - ADC_read(RIGHT_POT); 	// sum N samples
		l_pot_temp += 1023 - ADC_read(LEFT_POT);
	}
	r_pot_temp += 1 << (NUM_BSHIFT-1);           	// round result
	l_pot_temp += 1 << (NUM_BSHIFT-1);
	r_pot_temp >>= NUM_BSHIFT;                   	// Divide by N
	l_pot_temp >>= NUM_BSHIFT;

	// APPLY THRESHOLD TO SAMPLES
	if(abs(*L_pot - l_pot_temp) > THRESHOLD)
	{
		*L_pot = SCALE(l_pot_temp);
	}
	if(abs(*R_pot - r_pot_temp) > THRESHOLD)
	{
		*R_pot = SCALE(r_pot_temp);
	}
}

void draw(uint16 *x_prev, uint16 *y_prev)
{
	uint16 L_pot, R_pot;							// Gets new coordinates
	getCoordinates(&L_pot, &R_pot);

	if((*x_prev == L_pot) &&(*y_prev == R_pot))
	{
		return;
	}

	line(*x_prev, *y_prev, L_pot, R_pot);  		// output line
	*x_prev = L_pot;
	*y_prev = R_pot;

	counter = COUNTER;  									// Reset the BKLT timer

	int L = getNumChars(L_pot);
	int R = getNumChars(R_pot);
	int charLength = (L + R + 1+4);
	lcd_cursor(170 - charLength*6, 0);								// output coordinates
	lcd_printf("  %d,%d", L_pot, R_pot);
}

unsigned int getNumChars(uint16 num)
{
	uint16 amount_of_chars = 1;
	if(num >= 100)
	{
		amount_of_chars = 3;
	}
	else if (num >= 10)
	{
		amount_of_chars = 2;
	}
	return amount_of_chars;
}


//--Watchdog Timer ISR----------------------------------------------------------
//
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
	if (--WDT_cps_cnt == 0)						// 1 second?
	{
		WDT_cps_cnt = WDT_CPS;					// reset counter
		LED_GREEN_TOGGLE;						// toggle green LED
		if(counter > 0)
		{
			b_light = 1;
			counter--;
		}
		else
		{
			b_light = 0;
		}
		if(debounce_counter > 0)
		{
			debounce_counter--;
		}
	}
	return;
} // end WDT_ISR

//--PORT1 ISR------------------------------------------------------------------
//
#pragma vector = PORT1_VECTOR
__interrupt void Port_1_ISR(void)
{
	P1IFG &= ~0x0f; // (this recognizes if a switch has been pressed.)
	if(debounce_counter != 0)
	{
		return;
	}
	int button;
	button = P1IN;
	button &= 0x0f;
	button ^=0x0f;

	if(button == 1)
	{
		clear_lcd = 1;
	}
	else if(button == 2)
	{
		toggle_point_size = 1;
	}
	counter = COUNTER;
	debounce_counter = WDT_CPS*3/400;
	return;
}

unsigned int lowpass_filter_init(unsigned int input)
{
   return ((input << FILTER_SHIFT) + (input >> FILTER_SHIFT));
}

unsigned int lowpass_filter(unsigned int input, unsigned int* delay)
{
   *delay += input - (*delay >> FILTER_SHIFT); // update filter
   return *delay >> FILTER_SHIFT;              // scale output
}

void line(int x1, int y1, int x2, int y2)
{
    int dx, dy, inx, iny, e;

    dx = x2 - x1;
    dy = y2 - y1;
    inx = dx > 0 ? 1 : -1;
    iny = dy > 0 ? 1 : -1;

    dx = abs(dx);
    dy = abs(dy);

    if(dx >= dy) {
        dy <<= 1;
        e = dy - dx;
        dx <<= 1;
        while (x1 != x2) {
        	lcd_point(x1, y1, brush_size);
            if(e >= 0) {
                y1 += iny;
                e-= dx;
            }
            e += dy; x1 += inx;
        }
    } else {
        dx <<= 1;
        e = dx - dy;
        dy <<= 1;
        while (y1 != y2) {
        	lcd_point(x1, y1, brush_size);
            if(e >= 0) {
                x1 += inx;
                e -= dy;
            }
            e += dx; y1 += iny;
        }
    }
    lcd_point(x1, y1, brush_size);
}

